using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Device.Location;
using System.Windows;
using System.Windows.Media.Animation;
namespace Microsoft.Phone.Controls.Maps.Core
{
	public class MercatorMode : FlatMapMode
	{
		private const int refreshMilliseconds = 500;
		internal const string configurationVersion = "v1";
		internal const string configurationSection = "WP7SLMapControl";
		internal static readonly Size LogicalAreaSizeInScreenSpaceAtLevel1 = new Size(512.0, 512.0);
		private static readonly TimeSpan panningRefreshTime = new TimeSpan(0, 0, 0, 0, 100);
		private static readonly TimeSpan fullRefreshTime = new TimeSpan(0, 0, 0, 0);
		private static readonly long refreshTicks = new TimeSpan(0, 0, 0, 0, 500).get_Ticks();
		private readonly AttributionCollection attributions;
		private readonly ObservableCollection<AttributionInfo> attributionsBase;
		private readonly CopyrightManager copyright;
		private readonly Range<double> headingRange = new Range<double>(0.0, 0.0);
		private readonly Range<double> pitchRange = new Range<double>(-90.0, -90.0);
		private readonly Storyboard storyboardOnFrame;
		private readonly Range<double> zoomRange = new Range<double>(1.0, 21.0);
		private long lastOverlayRefresh = 9223372036854775807L;
		private bool projectionChangedFiredThisFrame;
		public override AttributionCollection Attributions
		{
			get
			{
				return this.attributions;
			}
		}
		public override double Heading
		{
			get
			{
				return 0.0;
			}
		}
		public override double Pitch
		{
			get
			{
				return -90.0;
			}
		}
		public override double Scale
		{
			get
			{
				return MercatorUtility.ZoomToScale(MercatorMode.LogicalAreaSizeInScreenSpaceAtLevel1, this.ZoomLevel, this.Center);
			}
			set
			{
				this.ZoomLevel = MercatorUtility.ScaleToZoom(MercatorMode.LogicalAreaSizeInScreenSpaceAtLevel1, value, this.Center);
			}
		}
		public override double TargetScale
		{
			get
			{
				return MercatorUtility.ZoomToScale(MercatorMode.LogicalAreaSizeInScreenSpaceAtLevel1, this.TargetZoomLevel, this.TargetCenter);
			}
		}
		public override Range<double> ZoomRange
		{
			get
			{
				return this.GetZoomRange(this.Center);
			}
		}
		public override Range<double> HeadingRange
		{
			get
			{
				return this.headingRange;
			}
		}
		public override Range<double> PitchRange
		{
			get
			{
				return this.pitchRange;
			}
		}
		public override LocationRect BoundingRectangle
		{
			get
			{
				Point topLeftLogicalPoint = base.ViewportPointToLogicalPoint(new Point(0.0, 0.0));
				Point bottomRightLogicalPoint = base.ViewportPointToLogicalPoint(new Point(base.ViewportSize.get_Width(), base.ViewportSize.get_Height()));
				return this.GetBoundingRectangle(topLeftLogicalPoint, bottomRightLogicalPoint);
			}
		}
		public override LocationRect TargetBoundingRectangle
		{
			get
			{
				Point topLeftLogicalPoint = base.TargetViewportDefinition.ViewportPointToLogicalPoint(new Point(0.0, 0.0));
				Point bottomRightLogicalPoint = base.TargetViewportDefinition.ViewportPointToLogicalPoint(new Point(base.ViewportSize.get_Width(), base.ViewportSize.get_Height()));
				return this.GetBoundingRectangle(topLeftLogicalPoint, bottomRightLogicalPoint);
			}
		}
		private Point CurrentLogicalCenter
		{
			get
			{
				Point viewportPoint = new Point(base.ViewportSize.get_Width() / 2.0, base.ViewportSize.get_Height() / 2.0);
				return base.CurrentViewportDefinition.ViewportPointToLogicalPoint(viewportPoint);
			}
		}
		public MercatorMode() : base(MercatorMode.LogicalAreaSizeInScreenSpaceAtLevel1)
		{
			this.attributionsBase = new ObservableCollection<AttributionInfo>();
			this.attributions = new AttributionCollection(this.attributionsBase);
			this.storyboardOnFrame = new Storyboard();
			this.storyboardOnFrame.add_Completed(new EventHandler(this.storyboardOnFrame_Completed));
			this.copyright = CopyrightManager.GetInstance();
		}
		protected override Point LocationToLogicalPoint(GeoCoordinate location)
		{
			return MercatorUtility.NormalizeLogicalPoint(MercatorUtility.LocationToLogicalPoint(location), this.CurrentLogicalCenter);
		}
		public override IEnumerable<Point> LocationToLogicalPoint(IEnumerable<GeoCoordinate> locations)
		{
			List<Point> list = new List<Point>();
			Point centerLogicalPoint = this.CurrentLogicalCenter;
			using (IEnumerator<GeoCoordinate> enumerator = locations.GetEnumerator())
			{
				while (enumerator.MoveNext())
				{
					GeoCoordinate current = enumerator.get_Current();
					Point point = MercatorUtility.NormalizeLogicalPoint(MercatorUtility.LocationToLogicalPoint(current), centerLogicalPoint);
					list.Add(point);
					centerLogicalPoint = point;
				}
			}
			return list;
		}
		public override Rect LocationRectToLogicalRect(LocationRect boundingRectangle)
		{
			GeoCoordinate geoCoordinate = new GeoCoordinate();
			geoCoordinate.set_Latitude(boundingRectangle.Center.get_Latitude() + boundingRectangle.Height / 2.0);
			geoCoordinate.set_Longitude(boundingRectangle.Center.get_Longitude() - boundingRectangle.Width / 2.0);
			Point point = MercatorUtility.LocationToLogicalPoint(geoCoordinate);
			GeoCoordinate geoCoordinate2 = new GeoCoordinate();
			geoCoordinate2.set_Latitude(boundingRectangle.Center.get_Latitude() - boundingRectangle.Height / 2.0);
			geoCoordinate2.set_Longitude(boundingRectangle.Center.get_Longitude() + boundingRectangle.Width / 2.0);
			Point point2 = MercatorUtility.LocationToLogicalPoint(geoCoordinate2);
			Point logicalPoint = MercatorUtility.LocationToLogicalPoint(boundingRectangle.Center);
			Point point3 = MercatorUtility.NormalizeLogicalPoint(logicalPoint, this.CurrentLogicalCenter);
			double num = point3.get_X() - logicalPoint.get_X();
			double num2 = point3.get_Y() - logicalPoint.get_Y();
			point.set_X(point.get_X() + num);
			point.set_Y(point.get_Y() + num2);
			point2.set_X(point2.get_X() + num);
			point2.set_Y(point2.get_Y() + num2);
			return new Rect(point, point2);
		}
		protected override GeoCoordinate LogicalPointToLocation(Point logicalPoint)
		{
			return MercatorUtility.NormalizeLocation(MercatorUtility.LogicalPointToLocation(logicalPoint));
		}
		public override bool ConstrainView(GeoCoordinate center, ref double zoomLevel, ref double heading, ref double pitch)
		{
			bool flag = false;
			GeoCoordinate geoCoordinate = MercatorUtility.NormalizeLocation(center);
			if (geoCoordinate != center)
			{
				flag = true;
				center.set_Latitude(geoCoordinate.get_Latitude());
				center.set_Longitude(geoCoordinate.get_Longitude());
				center.set_Altitude(geoCoordinate.get_Altitude());
			}
			double num = zoomLevel;
			Range<double> range = this.GetZoomRange(geoCoordinate);
			zoomLevel = Math.Min(zoomLevel, range.To);
			zoomLevel = Math.Max(zoomLevel, range.From);
			return flag || num != zoomLevel;
		}
		protected override void OnProjectionChanged(ProjectionUpdateLevel updateLevel)
		{
			base.OnProjectionChanged(updateLevel);
			this.UpdateAttribution(updateLevel);
		}
		protected virtual Range<double> GetZoomRange(GeoCoordinate center)
		{
			return this.zoomRange;
		}
		internal Range<double> GetZoomRange(TfeTileSource tileSource, GeoCoordinate center)
		{
			Range<double> range = this.zoomRange;
			double from = range.From;
			double num = range.To;
			if (tileSource != null && tileSource.CoverageMapLoaded)
			{
				Point point = this.LocationToLogicalPoint(center);
				if (point.get_X() < 0.0 || point.get_X() > 1.0)
				{
					point.set_X(point.get_X() - Math.Floor(point.get_X()));
				}
				if (point.get_Y() < 0.0)
				{
					point.set_Y(0.0);
				}
				else
				{
					if (point.get_Y() > 1.0)
					{
						point.set_Y(1.0);
					}
				}
				int num2 = (int)Math.Floor((double)tileSource.MaxZoomLevel);
				double num3 = Math.Pow(2.0, (double)num2) - 1.0;
				QuadKey quadKey = new QuadKey((int)Math.Round(point.get_X() * num3), (int)Math.Round(point.get_Y() * num3), num2);
				num = Math.Min(num, (double)tileSource.GetMaximumZoomLevel(quadKey));
			}
			return new Range<double>(from, num);
		}
		internal virtual void UpdateAttribution()
		{
		}
		internal void UpdateAttribution(IList<string> copyrightStrings)
		{
			Collection<string> collection = new Collection<string>(copyrightStrings);
			Collection<AttributionInfo> collection2 = new Collection<AttributionInfo>();
			using (IEnumerator<AttributionInfo> enumerator = this.attributionsBase.GetEnumerator())
			{
				while (enumerator.MoveNext())
				{
					AttributionInfo current = enumerator.get_Current();
					if (collection.Contains(current.Text))
					{
						collection.Remove(current.Text);
					}
					else
					{
						collection2.Add(current);
					}
				}
			}
			using (IEnumerator<AttributionInfo> enumerator2 = collection2.GetEnumerator())
			{
				while (enumerator2.MoveNext())
				{
					AttributionInfo current2 = enumerator2.get_Current();
					this.attributionsBase.Remove(current2);
				}
			}
			using (IEnumerator<string> enumerator3 = collection.GetEnumerator())
			{
				while (enumerator3.MoveNext())
				{
					string current3 = enumerator3.get_Current();
					this.attributionsBase.Add(new AttributionInfo
					{
						Text = current3
					});
				}
			}
		}
		internal void UpdateAttribution(ProjectionUpdateLevel updateLevel)
		{
			this.projectionChangedFiredThisFrame = true;
			long ticks = DateTime.get_Now().get_Ticks();
			if (ticks - this.lastOverlayRefresh >= MercatorMode.refreshTicks)
			{
				this.lastOverlayRefresh = ticks;
				this.UpdateAttribution();
				return;
			}
			if (this.lastOverlayRefresh > ticks)
			{
				this.lastOverlayRefresh = ticks;
			}
			if (updateLevel == ProjectionUpdateLevel.Full)
			{
				this.storyboardOnFrame.set_Duration(MercatorMode.fullRefreshTime);
			}
			else
			{
				this.storyboardOnFrame.set_Duration(MercatorMode.panningRefreshTime);
			}
			this.storyboardOnFrame.Begin();
		}
		internal static bool TryParseSubdomains(string subdomainString, out string[][] subdomains)
		{
			bool result = false;
			if (!string.IsNullOrEmpty(subdomainString))
			{
				string[] array = subdomainString.Split(new char[]
				{
					' '
				});
				subdomains = new string[array.Length][];
				for (int i = 0; i < array.Length; i++)
				{
					subdomains[i] = array[i].Split(new char[]
					{
						','
					});
				}
				result = true;
			}
			else
			{
				subdomains = null;
			}
			return result;
		}
		private void storyboardOnFrame_Completed(object sender, EventArgs e)
		{
			if (this.projectionChangedFiredThisFrame)
			{
				this.projectionChangedFiredThisFrame = false;
				this.storyboardOnFrame.Begin();
				return;
			}
			this.lastOverlayRefresh = 9223372036854775807L;
			this.UpdateAttribution();
		}
		private LocationRect GetBoundingRectangle(Point topLeftLogicalPoint, Point bottomRightLogicalPoint)
		{
			GeoCoordinate geoCoordinate = this.LogicalPointToLocation(topLeftLogicalPoint);
			GeoCoordinate geoCoordinate2 = this.LogicalPointToLocation(bottomRightLogicalPoint);
			GeoCoordinate geoCoordinate3 = this.LogicalPointToLocation(new Point((bottomRightLogicalPoint.get_X() + topLeftLogicalPoint.get_X()) / 2.0, 0.0));
			geoCoordinate3.set_Latitude((geoCoordinate.get_Latitude() + geoCoordinate2.get_Latitude()) / 2.0);
			double height = geoCoordinate.get_Latitude() - geoCoordinate2.get_Latitude();
			double num = bottomRightLogicalPoint.get_X() - topLeftLogicalPoint.get_X();
			num = ((num <= 1.0) ? (num * 360.0) : 360.0);
			return new LocationRect(geoCoordinate3, num, height);
		}
	}
}
